/*
 * Copyright (c) 2009 by Chances.
 * $CVSHeader: chances-commons/javasrc/commons/chances/commons/template/VelocityTemplateEngine.java,v 1.1 2009/07/14 08:14:49 libf Exp $
 * $Author: libf $
 * $Date: 2009/07/14 08:14:49 $
 * $Revision: 1.1 $
 */
package chances.epg.commons.template;

import java.io.Writer;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.VelocityException;
import org.apache.velocity.tools.generic.DateTool;
import org.apache.velocity.tools.generic.ListTool;
import org.springframework.ui.velocity.VelocityEngineUtils;

/**
 * 基于Velocity框架实现模板引擎.
 * 
 * @author <a href="mailto:libf@chances.com.cn">libf</a>
 */
public class VelocityTemplateEngine implements TemplateEngine {
	private VelocityEngine velocityEngine;
    private String encoding = "UTF-8";

    // 全局变量
    private Properties globalVar = new Properties();

    /**
     * 构造函数.
     */
    public VelocityTemplateEngine() {
        super();
    }

    /*
     * (non-Javadoc)
     * 
     * @see chances.commons.template.TemplateEngine#execute(java.lang.Object,
     *      java.io.Writer)
     */
    public void execute(Object obj, Writer writer) {
        if (obj == null) {
            throw new java.lang.IllegalArgumentException();
        }

        String vmName = getTemplateName(obj.getClass());
        this.execute(obj, vmName, writer);
    }

    /*
     * (non-Javadoc)
     * 
     * @see chances.commons.template.TemplateEngine#execute(java.lang.String,
     *      java.lang.Object, java.io.Writer)
     */
    public void execute(String vmName, Object obj, Writer writer) {
        if (obj == null) {
            throw new java.lang.IllegalArgumentException();
        }

        this.execute(obj, vmName, writer);
    }

    /*
     * (non-Javadoc)
     * 
     * @see chances.commons.template.TemplateEngine#execute(java.util.Collection,
     *      java.io.Writer)
     */
    public void execute(Collection<?> collection, Writer writer) {
        for (Object obj : collection) {
            this.execute(obj, writer);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see chances.commons.template.TemplateEngine#execute(java.util.Map,
     *      java.lang.String, java.io.Writer)
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public void execute(Map<?, ?> props, String vmName, Writer writer) {
        Map model = createModel();
        model.putAll(props);

        try {
        	VelocityEngineUtils.mergeTemplate(velocityEngine,vmName,encoding, model,
                    writer);
        } catch (VelocityException ex) {
            ex.printStackTrace();
        } finally{
        	model.clear();
        	model = null;
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see chances.commons.template.TemplateEngine#execute(java.util.Collection,
     *      java.lang.String, java.io.Writer)
     */
    public void execute(Collection<?> collection, String vmName, Writer writer) {
        for (Object object : collection) {
            this.execute(object, vmName, writer);
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public void execute(Object obj, String vmName, Writer writer) {
        Map model = this.createModel();
        model.put(this.getEntityVarName(obj), obj);

        try {
            VelocityEngineUtils.mergeTemplate(velocityEngine,vmName,encoding, model,
                    writer);
        } catch (VelocityException ex) {
            ex.printStackTrace();
        } finally{
        	model.clear();
        	model = null;
        }
    }

    /**
     * 创建Model.
     * 
     * @return
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    private Map createModel() {
        Map model = new HashMap();
        model.put("list", new ListTool());
        model.put("date", new DateTool());
        model.putAll(this.globalVar);

        return model;
    }

    /**
     * 根据类取得模板文件的相对路径.
     * 
     * @param clazz
     * @return
     */
    private String getTemplateName(Class<?> clazz) {
        String name = clazz.getName();
        name = name.replace('.', '/');

        return name + ".vm";
    }

    /**
     * 取得实体作为模板中变量的名称.
     * 
     * @param clazz
     * @return
     */
    private String getEntityVarName(Object obj) {
        String name = obj.getClass().getName();
        int idx = name.lastIndexOf(".");
        name = name.substring(idx + 1);

        return name.toLowerCase().charAt(0) + name.substring(1);
    }

    /**
     * @param velocityEngine
     *            the velocityEngine to set
     */
    public void setVelocityEngine(VelocityEngine velocityEngine) {
        this.velocityEngine = velocityEngine;
    }

    /**
     * @param globalVar
     *            the globalVar to set
     */
    public void setGlobalVar(Properties globalVar) {
        this.globalVar = globalVar;
    }

	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}
}
